package restart;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import game.tools.os.OSPlatforms;
import game.tools.parameters.ApplicationParameterTools;
import game.tools.utils.StringTools;

/**
 *  jenkins中配置脚本示例。
 *  set BUILD_ID=dontKillMe;
	call xcopy "combat-users/webapp" "D:/Data/Combat-Server/dev/users/webapp" /s /h /c /y /i /e
	cp combat-users/build/libs/combat-users.jar D:/Data/Combat-Server/dev/users/
	set path=C:\Program Files\Java\jdk-17.0.4.1\bin;
	java -jar D:\Data\Combat-Server\restart.jar app.name=combat-users.jar app.startup.dir=D:/Data/Combat-Server/dev/users/ app.startup.cmd=startup.bat
 *
 */
public class Restart 
{
	private static String appName, startupCmd , startupDir ;
	private static int startupWaitTime = 15_000;
	private static int checkCount = 50;
	
	public static void main(String[] args)  throws Exception
	{
		showParameters(args);
		restart(args);
	}
	
	private static void showParameters(String[] args) 
	{
		appName = ApplicationParameterTools.get(args, "app.name");
		startupDir = ApplicationParameterTools.get(args, "app.startup.dir");
		startupCmd = ApplicationParameterTools.get(args, "app.startup.cmd");
//		appName = "combat-users.jar";
//		startupDir = "D:/Git/users";
//		startupCmd = "startup.bat";
		
		game.tools.utils.ConsoleTable consoleTable = new game.tools.utils.ConsoleTable("参数描述","参数名称", "运行值");
		consoleTable.setTitle("运行时参数一览");
		consoleTable.addRow("应用程序名称 ", 		"app.name",				appName);
		consoleTable.addRow("启动目录", 			"app.startup.dir",		startupDir);
		consoleTable.addRow("启动命令", 			"app.startup.cmd",		startupCmd);
		System.out.println(consoleTable);
		
		if(StringTools.empty(appName))
			throw new RuntimeException("appName parameter is null。");
		
		if(StringTools.empty(startupDir) || StringTools.empty(startupCmd))
			throw new RuntimeException("startupDir or startupCmd parameter is null。");
	}

	private static void restart(String[] args)  throws Exception
	{
		int processId = getProcessId();
		killProcess(processId);
		checkKillProcess();
		startupProcess();
		checkStartupProcess();
	}
	
	private static void checkStartupProcess() throws Exception
	{
		int processId = 0;
		for (int i = 0; i < checkCount; i++) 
		{
			processId = getProcessId();
			if(processId != 0)
			{
				System.out.println("checkStartupProcess：startup success ! processId：" + processId);
				System.exit(0);
				return;
			}
			Thread.sleep(500);
			System.out.println("checkStartupProcess：check startup....");
		}
		System.exit(-1);
		throw new RuntimeException("checkStartupProcess：startup fail ! processId：" + processId);
	}

	private static void checkKillProcess() throws Exception
	{
		Thread.sleep(1000);
		int processId = 0;
		for (int i = 0; i < checkCount; i++) 
		{
			processId = getProcessId();
			if(processId == 0)
			{
				System.out.println("checkKillProcess：kill success !");
				return;
			}
			Thread.sleep(500);
			System.out.println("checkKillProcess：check process....");
		}
		System.exit(-2);
		throw new RuntimeException("checkKillProcess：kill fail！" + processId);
	}

	private static int startupProcess() throws Exception
	{
		String datetimeString = getCurrentTimeNumString();
		String cmdString = null;
		if(OSPlatforms.isWindows())
			cmdString = "cmd /c start /b " + startupCmd +" > out_"+datetimeString+".log 2>&1";
		else if(OSPlatforms.isLinux())
			cmdString = "nohup " + startupCmd + "> out_"+datetimeString+".log 2>&1 &";
		else if(OSPlatforms.isMacOS() || OSPlatforms.isMacOSX())
			cmdString = "nohup " + startupCmd + "> out_"+datetimeString+".log 2>&1 &";
		
		System.out.println("startupProcess.cmdString：" + cmdString);
		final Process process = Runtime.getRuntime().exec(cmdString , null , new File(startupDir));
		try 
		{
			Thread iReaderThread = new Thread(()->
			{
				String line = null;
				InputStream iStream = process.getInputStream();
				InputStreamReader iInputReader = new InputStreamReader(iStream , Charset.forName("gbk"));
				BufferedReader iReader = new BufferedReader(iInputReader);
				try 
				{
					do 
					{
						line = iReader.readLine();
						System.out.println("startupProcess.iResult：" + line);
					} while (line != null);
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				finally 
				{
					try 
					{
						if(iStream != null)
							iStream.close();
						if(iInputReader != null)
							iInputReader.close();
						if(iReader != null)
							iReader.close();
					}
					catch (IOException e)
					{
						e.printStackTrace();
					}
				}
			});
			
			Thread eReaderThread = new Thread(()->
			{
				String line = null;
				InputStream eStream = process.getErrorStream();
				InputStreamReader eInputReader = new InputStreamReader(eStream , Charset.forName("gbk"));
				BufferedReader eReader = new BufferedReader(eInputReader);
				try 
				{
					do
					{
						line = eReader.readLine();
						System.out.println("startupProcess.eResult：" + line);
					} while (line != null);
				}catch (IOException e)
				{
					e.printStackTrace();
				}
				finally 
				{
					try 
					{
						if(eStream != null)
							eStream.close();
						if(eInputReader != null)
							eInputReader.close();
						if(eReader != null)
							eReader.close();
					} 
					catch (IOException e)
					{
						e.printStackTrace();
					}
				}
			});
			
			iReaderThread.setDaemon(true);
			eReaderThread.setDaemon(true);
			
			iReaderThread.start();
			eReaderThread.start();
			
			Thread.sleep(startupWaitTime);
			System.out.println("startupProcess close reader");
		}
		finally 
		{
			if(process != null)
				process.destroy();
		}
		return 0;
	}
	
	private static String getCurrentTimeNumString() 
	{
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		return simpleDateFormat.format(new Date());
	}

	private static int killProcess(int processId) throws Exception
	{
		if(processId <= 0)
		{
			System.out.println("killProcess：not find process，processId：" + processId + "，ignore！");
			return 0;
		}
		
		String cmdString = null;
		if(OSPlatforms.isWindows())
			cmdString = "taskkill /f /pid " + processId;
		else if(OSPlatforms.isLinux())
			cmdString = "kill " + processId;
		else if(OSPlatforms.isMacOS() || OSPlatforms.isMacOSX())
			cmdString = "kill " + processId;

		System.out.println("killProcess.cmdString：" + cmdString);
		
		InputStream iStream = null;
		InputStreamReader inputReader = null;
		BufferedReader reader = null;
		Process process = null;
		try 
		{
			process = Runtime.getRuntime().exec(cmdString);
			iStream = process.getErrorStream();
			inputReader = new InputStreamReader(iStream , Charset.forName("gbk"));
			reader = new BufferedReader(inputReader);
			String line = null;
			do 
			{
				line = reader.readLine();
				System.out.println("killProcess.result：" + line);
			} while (line != null);
		}
		finally 
		{
			if(process != null)
				process.destroy();
			if(iStream != null)
				iStream.close();
			if(inputReader != null)
				inputReader.close();
			if(reader != null)
				reader.close();
		}
		return 0;
	}
	
	private static int getProcessId() throws Exception
	{
		InputStream iStream = null;
		InputStreamReader inputReader = null;
		BufferedReader reader = null;
		Process process = null;
		try 
		{
			process = Runtime.getRuntime().exec("jps");
			iStream = process.getInputStream();
			inputReader = new InputStreamReader(iStream);
			reader = new BufferedReader(inputReader);
			String line = null;
			do 
			{
				line = reader.readLine();
				if(line == null)
					break;

				System.out.println("getProcessId.result：" + line);
				if(line.indexOf(appName) > 0)
				{
					String [] array = line.split(" ");
					return Integer.parseInt(array[0]);
				}
			} while (line != null);
		}
		finally 
		{
			process.destroy();
			iStream.close();
			inputReader.close();
			reader.close();
		}
		return 0;
	}
	
}
